#include "engine.h"
#include <QScriptValueIterator>

#include <QScriptEngineDebugger>
#include <QMainWindow>


Processor::Processor(QString script)
{
    this->start();
    this->script = script;
}

void Processor::run()
{
    while(true)
    {
        semaphore.acquire();
        QScriptValue message(messageQueue.dequeue());
        QScriptValue processor = scriptEngine.newQObject(this);
        scriptEngine.globalObject().setProperty("message", message);
        scriptEngine.globalObject().setProperty("processor", processor);

        scriptEngine.evaluate(script);

    }
}

void Processor::link(Processor *processer)
{
    channels.append(processer);
}

void Processor::receive(QString message)
{
    messageQueue.enqueue(message);
    semaphore.release();
}

void Processor::setStatus(QString name, QString value)
{
    status[name] = value;
}

QString Processor::getStatus(QString name)
{
    return status[name];
}

void Processor::broadcast(QString message)
{
    for(int i = 0; i < channels.length(); i++)
        channels[i]->receive(message);
}

void Processor::log(QString message)
{
    qDebug()<<message;
}

Engine::Engine(QString topology, QString algorithm)
{
    QScriptEngine engine;
    QScriptValue configObject = engine.evaluate("(" + topology + ")");
    if(!configObject.isArray())
        throw QString("config invalid");

    int length = configObject.property("length").toInt32();
    for(int i = 0; i < length; i++)
    {
        Processor* processor = new Processor(algorithm);
        processor->setStatus("__id__", QString("%1").arg(i));
        processors.append(processor);
    }

    for(int i = 0; i < length; i++)
    {
        QScriptValue channels = configObject.property(i).property("channel");
        for(int j = 0; j < channels.property("length").toInt32(); j++)
            processors[i]->link(processors[channels.property(j).toInt32()]);
        QScriptValue status = configObject.property(i).property("status");
        QScriptValueIterator it(status);
        while(it.hasNext())
        {
            it.next();
            processors[i]->setStatus(it.name(), it.value().toString());
        }
    }


}

void Engine::run()
{

    for(int i=0; i < processors.length(); i++)
    {
        processors[i]->start();
    }
    processors[0]->receive("G");
}
